import React, { useContext, useState } from "react";

const appContext = React.createContext(null);

const store = {
    state: {
        user: {
            name: 'tom',
            age: 99
        }
    },
    setState (newState) {
        store.state = newState;
    }
}

const User = () => {
    console.log('User 组件')
    const { state } = useContext(appContext);
    return (
        <div>
            User: {state.user.name}
        </div>
    );
}

// reduce 用于规范 state 创建流程的函数
const reducer = (state, {type, payload = {}}) => {
    if (type === 'updateUser') {
        return {
            ...state,
            user: {
                ...state.user,
                ...payload
            }
        }
    } else {
        return state;
    }
}
// 高阶组件
const connect = (Component) => {
    const Wrapper = (props) => {
        const { state, setState } = useContext(appContext);
        const [, update] = useState({});
        // dispatch 用于规范 setState 的流程
        const dispatch = (action) => {
            setState(reducer(state, action));
            update({}); // 强制刷新 只会一个组件的更新,有 bug, 解决方案,使用发布订阅
        }
        return <Component {...props} dispatch={dispatch} state={state}/>
    }

    return Wrapper;
}

const UserModifier = connect(({dispatch, state, children}) => {
    console.log('UserModifier 组件')
    const changeHandler = (e) => {
        const newState = {
            type: 'updateUser',
            payload: {
                name: e.target.value
            }
        }
        dispatch(newState);
    }
    return (
        <div>
            {children}
            <input type="text" value={state.user.name} onChange={changeHandler}/>
        </div>
    );
});

const A = () => {
    console.log('A 组件')
    return <section>A 组件<User/></section>;
}
const B = () => {
    console.log('B 组件')
    return <section>B 组件<UserModifier num={1}>DDD</UserModifier></section>;
}
const C = () => {
    console.log('C 组件');
    return <section>C 组件</section>;
}

function App() {
    return (
        <appContext.Provider value={store}>
            <A/>
            <B/>
            <C/>
        </appContext.Provider>
    );
}

export default App;